﻿using Common;
using Common.Model;
using Newtonsoft.Json;
using RcsService.ParaModel;
using Serilog;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;

namespace OpticalComService.Services
{
    /// <summary>
    /// 向Rcs公开的接口业务处理
    /// </summary>
    public class RcsCallBackService
    {

        #region 属性
        private ConcurrentDictionary<string, string> WaitApplyReturnForBin = new ConcurrentDictionary<string, string>();
        #endregion

        /// <summary>
        /// 任务执行通知处理
        /// </summary>
        /// <returns></returns>
        public async Task<ResultPara> AgvCallbackProcess(ExecuteResponsePara para)
        {
            
            var msg = JsonConvert.SerializeObject(
                CreatIpticalInfo(ConstString.agvCallbackCode,para.reqCode, JsonConvert.SerializeObject(para)))
                + ConstString.Termination;
            var flag = await OpticalInitService.Instance.SendOpticalMsgProcess(msg);

            var result = flag ? CreatResultData(para.reqCode) : CreatResultDataFail(para.reqCode);

            return result;
        }
        /// <summary>
        /// 告警推送通知处理 
        /// </summary>
        /// <returns></returns>
        public async Task<ResultPara> WarnCallbackProcess(WarnPara para)
        {
            var msg = JsonConvert.SerializeObject(
               CreatIpticalInfo(ConstString.warnCallbackCode, para.reqCode, JsonConvert.SerializeObject(para)))
                + ConstString.Termination;
            var flag = await OpticalInitService.Instance.SendOpticalMsgProcess(msg);
            var result = flag ? CreatResultData(para.reqCode) : CreatResultDataFail(para.reqCode);

            return result;
        }
        /// <summary>
        /// 绑定解绑通知
        /// </summary>
        /// <returns></returns>
        public async Task<ResultDataPara> BindNotifyProcess(BindNotifyPara para)
        {
            var msg = JsonConvert.SerializeObject(
               CreatIpticalInfo(ConstString.bindNotifyCode, para.reqCode, JsonConvert.SerializeObject(para)))
                + ConstString.Termination;
            var flag = await OpticalInitService.Instance.SendOpticalMsgProcess(msg);
            var result = flag ? CreatResultInData(para.reqCode) : CreatResultInDataFail(para.reqCode);
            return result;
        }
        /// <summary>
        /// 校验料箱是否可入库（CTU）
        /// </summary>
        /// <returns></returns>
        public async Task<ResultPara> ApplyReturnForValidProcess(ApplyReturnForValidPara para)
        {
            var msg = JsonConvert.SerializeObject(
               CreatIpticalInfo(ConstString.applyReturnForValidCode, para.reqCode, JsonConvert.SerializeObject(para)))
                + ConstString.Termination;
            var flag = await OpticalInitService.Instance.SendOpticalMsgProcess(msg);
            var result = flag ? CreatResultData(para.reqCode) : CreatResultDataFail(para.reqCode);
            return result;
        }
        /// <summary>
        /// 申请回库仓位（CTU） 
        /// </summary>
        /// <returns></returns>
        public async Task<ApplyReturnForBinResultPara> ApplyReturnForBinProcess(ApplyReturnForBinPara para)
        {
            var msg = JsonConvert.SerializeObject(
              CreatIpticalInfo(ConstString.applyReturnForBinCode, para.reqCode, JsonConvert.SerializeObject(para)))
                + ConstString.Termination;
            //添加至等待回复队列中
            var addFlag = await OpticalInitService.Instance.AddWaitResultQueueAsync(para.reqCode, ApplyReturnForBinExecute);
            if (!addFlag)
            {
                Log.Error($"将需要等待回复的服务添加到等待队列中失败!");
                return CreatApplyReturnForBinFail(para.reqCode);
            }
            var flag = await OpticalInitService.Instance.SendOpticalMsgProcess(msg);

            if (!flag)
            {
                await OpticalInitService.Instance.RemoveWaitQueueAsync(para.reqCode);
                return CreatApplyReturnForBinFail(para.reqCode);
            }
            //等待WCS回复
            var resultInfo = await GetApplyReturnForBinInfoAsync(para.reqCode);
            var result = CreatApplyReturnForBin(para.reqCode, resultInfo);

            return result;
        }

        private async Task ApplyReturnForBinExecute(string reqCode,string msg)
        {
            await Task.Run(() => 
            {
                WaitApplyReturnForBin.AddOrUpdate(reqCode, msg, (key, value) => value);
            });
        }

        private async Task<string> GetApplyReturnForBinInfoAsync(string reqCode)
        { 
            string result =string.Empty;
            CancellationTokenSource cts = new CancellationTokenSource();
            cts.CancelAfter(5000);
            string resultInfo = string.Empty;
            await Task.Run(() => 
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    if (WaitApplyReturnForBin.ContainsKey(reqCode))
                    {
                        WaitApplyReturnForBin.TryGetValue(reqCode,out string info);
                        resultInfo = info;
                    }
                }
            });
           
            return resultInfo;
        }

        /// <summary>
        /// 创建用于光通信的参数
        /// </summary>
        /// <param name="funCode"></param>
        /// <param name="reqCode"></param>
        /// <param name="eqCode"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private OpticalInfoModel CreatIpticalInfo(string funCode,string reqCode,string data)
        {
            OpticalInfoModel result = new OpticalInfoModel();
            result.funCode = funCode;
            result.number = reqCode;
            result.EqCode = AppSetting.Instance.EqCode;
            result.data = data;
            result.dataLen = data.Length;
            return result;
        }
        private ApplyReturnForBinResultPara CreatApplyReturnForBinFail(string reqCode)
        {
            ApplyReturnForBinResultPara result = new ApplyReturnForBinResultPara();
            var resultInfo = CreatResultDataFail(reqCode);
            result.code = resultInfo.code;
            result.message = resultInfo.message;
            result.reqCode = resultInfo.reqCode;
            return result;
        }
        private ApplyReturnForBinResultPara CreatApplyReturnForBin(string reqCode,string data)
        {
            ApplyReturnForBinResultPara result = new ApplyReturnForBinResultPara();
            var resultInfo = CreatResultData(reqCode);
            result.code = resultInfo.code;
            result.message = resultInfo.message;
            result.reqCode = resultInfo.reqCode;
            var info = JsonConvert.DeserializeObject<List<ApplyReturnForBinResultData>>(data);
            //需要光通信回复
            result.data = info;
            return result;
        }

        private ResultDataPara CreatResultInDataFail(string reqCode)
        {
            ResultDataPara result = new ResultDataPara();
            var resultInfo = CreatResultDataFail(reqCode);
            result.code = resultInfo.code;
            result.message = resultInfo.message;
            result.reqCode = resultInfo.reqCode;

            return result;
        }

        private ResultDataPara CreatResultInData(string reqCode)
        {
            ResultDataPara result = new ResultDataPara();
            var resultInfo = CreatResultData(reqCode);
            result.code = resultInfo.code;
            result.message = resultInfo.message;
            result.reqCode = resultInfo.reqCode;

            return result;
        }

        private ResultPara CreatResultData(string reqCode)
        {
            ResultPara result = new ResultPara();
            result.code = ConstString.ResultCode_success;
            result.message = ConstString.ResultMsg_success;
            result.reqCode = reqCode;

            return result;
        }

        private ResultPara CreatResultDataFail(string reqCode)
        {
            ResultPara result = new ResultPara();
            result.code = ConstString.ResultCode_fail;
            result.message = ConstString.ResultMsg_fail;
            result.reqCode = reqCode;

            return result;
        }
    }
}
